package com.lemon.core.validator.utils;

import java.util.regex.Pattern;

/**
 * 常用正则表达式集合
 *
 * @author Looly
 */
public class PatternPool {

    /**
     * 英文字母 、数字和下划线
     */
    private static final String REGEX_GENERAL = "^\\w+$";
    public static final Pattern PATTERN_REGEX_GENERAL = Pattern.compile(REGEX_GENERAL);
    /**
     * 数字
     */
    private static final String REGEX_NUMBERS = "\\d+";
    public static final Pattern PATTERN_REGEX_NUMBERS = Pattern.compile(REGEX_NUMBERS);
    /**
     * 银行卡号 只校验数字 非Luhn校验
     */
    private static final String REGEX_CARD_NO = "^[1-9]\\d{10,22}$";
    public static final Pattern PATTERN_REGEX_CARD_NO = Pattern.compile(REGEX_CARD_NO);
    /**
     * 单个中文汉字
     */
    private static final String REGEX_CHINESE = "[\u4E00-\u9FFF]";
    public static final Pattern PATTERN_REGEX_CHINESE = Pattern.compile(REGEX_CHINESE);
    /**
     * 中文汉字
     */
    private static final String REGEX_CHINESES = "[\u4E00-\u9FFF]+";
    public static final Pattern PATTERN_REGEX_CHINESES = Pattern.compile(REGEX_CHINESES);
    /**
     * 分组
     */
    private static final String REGEX_GROUP_VAR = "\\$(\\d+)";
    public static final Pattern PATTERN_REGEX_GROUP_VAR = Pattern.compile(REGEX_GROUP_VAR);
    /**
     * IP v4
     */
    private static final String REGEX_IPV4 =
        "\\b((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\b";
    public static final Pattern PATTERN_REGEX_IPV4 = Pattern.compile(REGEX_IPV4);
    /**
     * 货币
     */
    private static final String REGEX_MONEY = "^(\\d+(?:\\.\\d+)?)$";
    public static final Pattern PATTERN_REGEX_MONEY = Pattern.compile(REGEX_MONEY);
    /**
     * 邮件，符合RFC 5322规范，正则来自：http://emailregex.com/ /[a-zA-Z_]{1,}[0-9]{0,}@(([a-zA-z0-9]-*){1,}\\.){1,3}[a-zA-z\\-]{1,}$
     */
    private static final String REGEX_EMAIL =
        "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])";
    public static final Pattern PATTERN_REGEX_EMAIL = Pattern.compile(REGEX_EMAIL);
    /**
     * 移动电话
     */
    private static final String REGEX_MOBILE = "(?:0|86|\\+86)?1[3456789]\\d{9}";
    public static final Pattern PATTERN_REGEX_MOBILE = Pattern.compile(REGEX_MOBILE);
    /**
     * 18位身份证号码
     */
    private static final String REGEX_CITIZEN_ID =
        "[1-9]\\d{5}[1-2]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}(\\d|X|x)";
    public static final Pattern PATTERN_REGEX_CITIZEN_ID = Pattern.compile(REGEX_CITIZEN_ID);
    /**
     * 邮编
     */
    private static final String REGEX_ZIP_CODE = "\\d{6}";
    public static final Pattern PATTERN_REGEX_ZIP_CODE = Pattern.compile(REGEX_ZIP_CODE);
    /**
     * 生日
     */
    private static final String REGEX_BIRTHDAY = "^(\\d{2,4})([/\\-\\.年]?)(\\d{1,2})([/\\-\\.月]?)(\\d{1,2})日?$";
    public static final Pattern PATTERN_REGEX_BIRTHDAY = Pattern.compile(REGEX_BIRTHDAY);
    /**
     * URL
     */
    private static final String REGEX_URL = "(https://|http://)?([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?";
    public static final Pattern PATTERN_REGEX_URL = Pattern.compile(REGEX_URL);
    /**
     * 中文字、英文字母、数字和下划线
     */
    private static final String REGEX_GENERAL_WITH_CHINESE = "^[\u4E00-\u9FFF\\w]+$";
    public static final Pattern PATTERN_REGEX_GENERAL_WITH_CHINESE = Pattern.compile(REGEX_GENERAL_WITH_CHINESE);
    /**
     * UUID
     */
    private static final String REGEX_UUID = "^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$";
    public static final Pattern PATTERN_REGEX_UUID = Pattern.compile(REGEX_UUID);
    /**
     * 不带横线的UUID
     */
    private static final String REGEX_UUID_SIMPLE = "^[0-9a-z]{32}$";
    public static final Pattern PATTERN_REGEX_UUID_SIMPLE = Pattern.compile(REGEX_UUID_SIMPLE);
    /**
     * 中国车牌号码
     */
    private static final String REGEX_PLATE_NUMBER =
        "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$";
    public static final Pattern PATTERN_REGEX_PLATE_NUMBER = Pattern.compile(REGEX_PLATE_NUMBER);
    /**
     * MAC地址正则
     */
    private static final String REGEX_MAC_ADDRESS =
        "((?:[A-F0-9]{1,2}[:-]){5}[A-F0-9]{1,2})|(?:0x)(\\d{12})(?:.+ETHER)";
    public static final Pattern PATTERN_REGEX_MAC_ADDRESS =
        Pattern.compile(REGEX_MAC_ADDRESS, Pattern.CASE_INSENSITIVE);
    /**
     * Pattern池
     */
    private static final SimpleCache<RegexWithFlag, Pattern> POOL = new SimpleCache<>();

    // -------------------------------------------------------------------------------------------------------------------------------------------------------------------

    /**
     * 私有化构造方法
     */
    private PatternPool() {}

    /**
     * 先从Pattern池中查找正则对应的{@link Pattern}，找不到则编译正则表达式并入池。
     *
     * @param regex
     *            正则表达式
     * @return {@link Pattern}
     */
    public static Pattern get(String regex) {
        return get(regex, 0);
    }

    /**
     * 先从Pattern池中查找正则对应的{@link Pattern}，找不到则编译正则表达式并入池。
     *
     * @param regex
     *            正则表达式
     * @param flags
     *            正则标识位集合 {@link Pattern}
     * @return {@link Pattern}
     */
    public static Pattern get(String regex, int flags) {
        final RegexWithFlag regexWithFlag = new RegexWithFlag(regex, flags);

        Pattern pattern = POOL.get(regexWithFlag);
        if (null == pattern) {
            pattern = Pattern.compile(regex, flags);
            POOL.put(regexWithFlag, pattern);
        }
        return pattern;
    }

    /**
     * 移除缓存
     *
     * @param regex
     *            正则
     * @param flags
     *            标识
     * @return 移除的{@link Pattern}，可能为{@code null}
     */
    public static Pattern remove(String regex, int flags) {
        return POOL.remove(new RegexWithFlag(regex, flags));
    }

    /**
     * 清空缓存池
     */
    public static void clear() {
        POOL.clear();
    }

    // ---------------------------------------------------------------------------------------------------------------------------------

    /**
     * 正则表达式和正则标识位的包装
     *
     * @author Looly
     */
    private static class RegexWithFlag {
        private String regex;
        private int flag;

        /**
         * 构造
         *
         * @param regex
         *            正则
         * @param flag
         *            标识
         */
        public RegexWithFlag(String regex, int flag) {
            this.regex = regex;
            this.flag = flag;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + flag;
            result = prime * result + ((regex == null) ? 0 : regex.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            RegexWithFlag other = (RegexWithFlag)obj;
            if (flag != other.flag) {
                return false;
            }
            if (regex == null) {
                if (other.regex != null) {
                    return false;
                }
            } else if (!regex.equals(other.regex)) {
                return false;
            }
            return true;
        }

    }
}
